home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xwall
/
xwalld.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-20
|
16KB
|
580 lines
/*
* Copyright 1990 University of Wisconsin-Madison
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the University of Wisconsin-Madison not
* be used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. The University of
* Wisconsin-Madison makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* THE UNIVERSITY OF WISCONSIN-MADISON DISCLAIMS ALL WARRANTIES WITH REGARD TO
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN-MADISON BE LIABLE FOR
* ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Tim Theisen Department of Computer Sciences
* tim@cs.wisc.edu University of Wisconsin-Madison
* uwvax!tim 1210 West Dayton Street
* (608)262-0438 Madison, WI 53706
*/
#include <stdio.h>
#include <signal.h>
#include <X11/Xos.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xatom.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xmu/Atoms.h>
#include "patchlevel.h"
#ifdef SIGNALRETURNSINT
#define SIGVAL int
#else
#define SIGVAL void
#endif
/* Respawning is only necessary for X11R4. */
/* For X11R5, xwalld is run in the Xsetup script. */
#ifndef XlibSpecificationRelease
#define RESPAWN
#endif
typedef struct _AppResources {
int openDelay;
int pingInterval;
int pingTimeout;
Boolean bell, daemon, notify, raise;
} AppResources;
AppResources app_resources = {15, 5, 5, True, True, True, True};
static XtResource resources[] = {
{"openDelay", "OpenDelay", XtRInt, sizeof(int),
XtOffsetOf(AppResources, openDelay), XtRImmediate, (XtPointer)15},
{"pingInterval", "PingInterval", XtRInt, sizeof(int),
XtOffsetOf(AppResources, pingInterval), XtRImmediate, (XtPointer)5},
{"pingTimeout", "PingTimeout", XtRInt, sizeof(int),
XtOffsetOf(AppResources, pingTimeout), XtRImmediate, (XtPointer)5},
{"bell", "Bell", XtRBoolean, sizeof(Boolean),
XtOffsetOf(AppResources, bell), XtRImmediate, (XtPointer)True},
{"daemon", "Daemon", XtRBoolean, sizeof(Boolean),
XtOffsetOf(AppResources, daemon), XtRImmediate, (XtPointer)True},
{"notify", "Notify", XtRBoolean, sizeof(Boolean),
XtOffsetOf(AppResources, notify), XtRImmediate, (XtPointer)True},
{"raise", "Raise", XtRBoolean, sizeof(Boolean),
XtOffsetOf(AppResources, raise), XtRImmediate, (XtPointer)True},
};
static XrmOptionDescRec options[] = {
{"-bell", ".bell", XrmoptionNoArg, (caddr_t)"on"},
{"-nobell", ".bell", XrmoptionNoArg, (caddr_t)"off"},
{"-daemon", ".daemon", XrmoptionNoArg, (caddr_t)"on"},
{"-nodaemon", ".daemon", XrmoptionNoArg, (caddr_t)"off"},
{"-notify", ".notify", XrmoptionNoArg, (caddr_t)"on"},
{"-nonotify", ".notify", XrmoptionNoArg, (caddr_t)"off"},
{"-raise", ".raise", XrmoptionNoArg, (caddr_t)"on"},
{"-noraise", ".raise", XrmoptionNoArg, (caddr_t)"off"},
};
static void Deiconified();
static void Iconified();
static void delete_window();
static XtActionsRec actions[] = {
{"Deiconified", Deiconified},
{"Iconified", Iconified},
{"Delete", delete_window},
};
String fallback_resources[] = {
# include "Xwall.ad.h"
NULL};
static void Syntax();
static void make_wall_popup();
extern char *malloc();
static SIGVAL catchALRM();
#ifdef RESPAWN
static String *saved_argv;
static int saved_argc;
static SIGVAL catchHUP();
static int catchXError();
static int catchXIOError();
static void catchXtError();
static void respawn();
static int connected;
#endif
XtAppContext app_con;
static Display *dpy;
static XtIntervalId timer_id;
static void pingDisplay();
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel;
#ifdef RESPAWN
int i;
XErrorHandler oldXError;
XIOErrorHandler oldXIOError;
saved_argc = argc;
saved_argv = (String *) malloc((saved_argc + 1) * sizeof(String));
if (saved_argv == NULL) {
fprintf(stderr, "%s: Malloc failure!\n, argv[0]");
exit(1);
}
for (i = 0 ; i < saved_argc ; i++) saved_argv[i] = argv[i];
saved_argv[i] = NULL; /* NULL terminate that sucker. */
/* make ourselves fairly bullet proof */
(void) signal(SIGHUP, catchHUP);
oldXError = XSetErrorHandler (catchXError);
oldXIOError = XSetIOErrorHandler (catchXIOError);
XtSetErrorHandler (catchXtError);
/* If we are root, Become daemon right away. */
/* (Don't want to hold up /etc/rc.) */
if (getuid() == 0) {
BecomeOrphan();
BecomeDaemon();
/* If starting from rc wait for */
sleep(app_resources.openDelay); /* xdm to get the X server ready */
}
/* Use root Xauthority file. Automatically refreshed upon display reset */
setuid(0);
(void) setenv("XAUTHORITY", "/.Xauthority", True);
#endif
XtToolkitInitialize();
app_con = XtCreateApplicationContext();
XtAppAddActions(app_con, actions, XtNumber(actions));
XtAppSetFallbackResources(app_con, fallback_resources);
(void) signal (SIGALRM, catchALRM);
(void) alarm (app_resources.pingTimeout*60);
dpy = XtOpenDisplay(app_con, NULL, NULL, "Xwall",
options, XtNumber(options), &argc, argv);
(void) alarm(0);
#ifdef RESPAWN
if (dpy == NULL) respawn();
connected = 1;
#else
if (dpy == NULL) exit(1);
#endif
toplevel = XtAppCreateShell(NULL, "Xwall", applicationShellWidgetClass,
dpy, NULL, ZERO);
if (argc != 1)
Syntax(argv[0]);
XtGetApplicationResources(toplevel, (XtPointer) &app_resources,
resources, XtNumber(resources), NULL, ZERO);
if (app_resources.daemon) {
BecomeOrphan();
BecomeDaemon();
}
/* Ping the display if it is remote */
if (*DisplayString(dpy) != ':') {
timer_id = XtAppAddTimeOut(app_con, app_resources.pingInterval*60*1000,
pingDisplay, (XtPointer) 0);
}
make_wall_popup(toplevel);
XtAppMainLoop(app_con);
}
static void
Syntax(call)
char *call;
{
XtDestroyApplicationContext(app_con);
fprintf(stderr, "Usage: %s\n", call);
fprintf(stderr, " [-display <display>]\n");
fprintf(stderr, " [-[no]bell] [-[no]notify] [-[no]raise]\n");
exit(1);
}
static void
pingDisplay(data, id)
XtPointer data;
XtIntervalId *id;
{
(void) alarm (app_resources.pingTimeout*60);
XSync(dpy, 0);
(void) alarm(0);
timer_id = XtAppAddTimeOut(app_con, app_resources.pingInterval*60*1000,
pingDisplay, (XtPointer) 0);
}
#ifdef RESPAWN
static SIGVAL
catchALRM()
{
respawn();
}
static SIGVAL
catchHUP()
{
respawn();
}
static int
catchXError(dpy, xev)
Display *dpy;
XErrorEvent *xev;
{
connected = 1;
respawn();
}
static int
catchXIOError(dpy)
Display *dpy;
{
connected = 1;
respawn();
}
static void
catchXtError(msg)
String msg;
{
connected = 1;
respawn();
}
static void
respawn()
{
if (!connected) /* If we were not connected */
sleep(app_resources.pingInterval*60);
/* Restart ourself */
execvp(saved_argv[0], saved_argv);
}
#else
static SIGVAL
catchALRM()
{
exit(1);
}
#endif
#define LINES 10
static Time GetTime();
static void LoseSelection();
static Boolean RefuseSelection();
static void LoseManager();
static void InsertMessage();
static void dismiss();
static void Notify();
static Atom message, manager;
static Atom wm_delete_window; /* Atom sent to destroy a window */
static Boolean notified;
static Boolean iconified;
static Widget wall, form, title, text, button;
static int message_length;
static XawTextBlock message_block;
static void
make_wall_popup(parent)
Widget parent;
{
XFontStruct *font;
Dimension bottomMargin, leftMargin, rightMargin, topMargin;
Dimension width, height;
Arg args[9];
wm_delete_window = XInternAtom(XtDisplay(parent), "WM_DELETE_WINDOW",
False);
wall = XtCreatePopupShell("wall", topLevelShellWidgetClass,
parent, NULL, ZERO);
form = XtCreateManagedWidget("form", formWidgetClass,
wall, NULL, ZERO);
XtSetArg(args[0], XtNfromVert, NULL);
XtSetArg(args[1], XtNresize, False);
XtSetArg(args[2], XtNborderWidth, 0);
XtSetArg(args[3], XtNtop, XtChainTop);
XtSetArg(args[4], XtNbottom, XtChainTop);
XtSetArg(args[5], XtNleft, XtChainLeft);
XtSetArg(args[6], XtNright, XtChainRight);
title = XtCreateManagedWidget("title", labelWidgetClass,
form, args, SEVEN);
XtSetArg(args[0], XtNfromVert, title);
XtSetArg(args[1], XtNscrollHorizontal, XawtextScrollWhenNeeded);
XtSetArg(args[2], XtNscrollVertical, XawtextScrollWhenNeeded);
XtSetArg(args[3], XtNdisplayCaret, False);
XtSetArg(args[4], XtNdisplayNonprinting, False);
XtSetArg(args[5], XtNtop, XtChainTop);
XtSetArg(args[6], XtNbottom, XtChainBottom);
XtSetArg(args[7], XtNleft, XtChainLeft);
XtSetArg(args[8], XtNright, XtChainRight);
text = XtCreateManagedWidget("message", asciiTextWidgetClass,
form, args, NINE);
XtSetArg(args[0], XtNfromVert, text);
XtSetArg(args[1], XtNresize, False);
XtSetArg(args[2], XtNtop, XtChainBottom);
XtSetArg(args[3], XtNbottom, XtChainBottom);
XtSetArg(args[4], XtNleft, XtChainLeft);
XtSetArg(args[5], XtNright, XtChainRight);
button = XtCreateManagedWidget("button", commandWidgetClass,
form, args, SIX);
XtAddCallback(button, XtNcallback, dismiss, NULL);
XtInstallAccelerators(wall, button);
XtSetArg(args[0], XtNfont, &font);
XtSetArg(args[1], XtNbottomMargin, &bottomMargin);
XtSetArg(args[2], XtNleftMargin, &leftMargin);
XtSetArg(args[3], XtNrightMargin, &rightMargin);
XtSetArg(args[4], XtNtopMargin, &topMargin);
XtGetValues(text, args, FIVE);
width = font->max_bounds.width * 80 + leftMargin + rightMargin;
height = (font->ascent + font->descent) * LINES + topMargin + bottomMargin;
XtSetArg(args[0], XtNwidth, width);
XtSetArg(args[1], XtNheight, height);
XtSetValues(title, args, ONE);
XtSetValues(text, args, TWO);
XtSetValues(button, args, ONE);
XtRealizeWidget(wall);
XSetWMProtocols(XtDisplay(wall), XtWindow(wall), &wm_delete_window, 1);
manager = XInternAtom(XtDisplay(text), "MESSAGE_MANAGER", False);
while (!XtOwnSelection(text, manager, GetTime(wall),
RefuseSelection, LoseManager, NULL)) {}
message = XInternAtom(XtDisplay(text), "MESSAGE", False);
while (!XtOwnSelection(text, message, GetTime(wall),
RefuseSelection, LoseSelection, NULL)) {}
}
static Time
GetTime(w)
Widget w;
{
XSetWindowAttributes attributes;
static Window myw;
Time now = 0;
XEvent event;
Display *dpy = XtDisplay(w);
/* Create an unmapped window, that the window manager will ignore.
* This invisble window will be used to do a zero lenght property
* append. The event returned furnishes the timestamp */
if (!myw) {
attributes.override_redirect = True;
attributes.event_mask = PropertyChangeMask;
myw = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect|CWEventMask, &attributes);
}
XChangeProperty(dpy, myw, XA_NULL(dpy), XA_NULL(dpy), 8,
PropModeAppend, NULL, 0);
while (now == 0) {
XtAppNextEvent(app_con, &event);
if ((event.type == PropertyNotify) && (event.xproperty.window == myw) &&
(event.xproperty.atom == XA_NULL(dpy)))
now = event.xproperty.time;
else
XtDispatchEvent(&event);
}
return(now);
}
static void
LoseSelection(w, selection)
Widget w;
Atom *selection;
{
XtGetSelectionValue(w, *selection, XA_STRING, InsertMessage,
NULL, GetTime(w));
}
/*ARGSUSED*/
static Boolean
RefuseSelection(w, selection, target, type, value, length, format)
Widget w;
Atom *selection, *target, *type;
XtPointer *value;
unsigned long *length;
int *format;
{
return False;
}
/*ARGSUSED*/
static void
LoseManager(w, selection)
Widget w;
Atom *selection;
{
XtDestroyApplicationContext(app_con);
exit(0);
}
static void
InsertMessage(w, client_data, selection, type, value, length, format)
Widget w;
XtPointer client_data;
Atom *selection, *type;
XtPointer value;
unsigned long *length;
int *format;
{
Arg args[2];
if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0) {
while (!XtOwnSelection(w, message, GetTime(w),
RefuseSelection, LoseSelection, NULL)) {}
return;
}
message_block.firstPos = 0;
message_block.length = *length;
message_block.ptr = value;
message_block.format = FMT8BIT;
XawTextDisableRedisplay(text);
XtSetArg(args[0], XtNeditType, XawtextAppend);
XtSetValues(text, args, ONE);
XawTextReplace(text, message_length, message_length, &message_block);
message_length = message_length + message_block.length;
XtSetArg(args[0], XtNeditType, XawtextRead);
XtSetArg(args[1], XtNinsertPosition, message_length);
XtSetValues(text, args, TWO);
XawTextEnableRedisplay(text);
XtPopup(wall, XtGrabNone);
if (app_resources.raise) XMapRaised(XtDisplay(wall), XtWindow(wall));
if (app_resources.bell) XBell(XtDisplay(wall), 0);
if (app_resources.notify) Notify();
while (!XtOwnSelection(w, message, GetTime(w),
RefuseSelection, LoseSelection, NULL)) {}
XtFree(value);
}
static void
dismiss(w, client_data, call_data)
Widget w;
XtPointer call_data, client_data;
{
Arg args[2];
XtPopdown(wall);
XtSetArg(args[0], XtNeditType, XawtextEdit);
XtSetArg(args[1], XtNinsertPosition, 0);
XtSetValues(text, args, TWO);
message_block.length = 0;
XawTextReplace(text, 0, message_length, &message_block);
XtSetArg(args[0], XtNeditType, XawtextRead);
XtSetValues(text, args, ONE);
message_length = 0;
}
/* Implement WM_DELETE_WINDOW protocol */
static void
delete_window(w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
if (event->type == ClientMessage &&
event->xclient.data.l[0] != wm_delete_window) return;
dismiss(w, (XtPointer)NULL, (XtPointer)NULL);
}
static void
Notify ()
{
Arg arglist[1];
char *oldName;
char *newName;
if (!iconified || !app_resources.notify || notified)
return;
XtSetArg (arglist[0], XtNiconName, &oldName);
XtGetValues (wall, arglist, 1);
newName = malloc (strlen (oldName) + 3);
if (!newName)
return;
sprintf (newName, "%s *", oldName);
XtSetArg (arglist[0], XtNiconName, newName);
XtSetValues (wall, arglist, 1);
free (newName);
notified = True;
}
/*ARGSUSED*/
static void
Deiconified (widget, event, params, num_params)
Widget widget;
XEvent *event;
String *params;
Cardinal *num_params;
{
Arg arglist[1];
char *oldName;
char *newName;
int oldlen;
iconified = False;
if (!app_resources.notify || !notified)
return;
XtSetArg (arglist[0], XtNiconName, &oldName);
XtGetValues (wall, arglist, 1);
oldlen = strlen (oldName);
if (oldlen >= 2) {
newName = malloc (oldlen - 1);
if (!newName)
return;
strncpy (newName, oldName, oldlen - 2);
newName[oldlen - 2] = '\0';
XtSetArg (arglist[0], XtNiconName, newName);
XtSetValues (wall, arglist, 1);
free (newName);
}
notified = False;
}
/*ARGSUSED*/
static void
Iconified (widget, event, params, num_params)
Widget widget;
XEvent *event;
String *params;
Cardinal *num_params;
{
iconified = True;
}